
#ifndef BeiXiangDtu_h
#define BeiXiangDtu_h

#include "ESP32Hardware.cpp"
#include "IHardwareInterface.h"
#include "NetChannel.h"
#include "OTAUpdater.h"
#include "Ping.h"
#include "Profile.h"
#include "SerialMessageQueueManager.h"
#include "cJSON.h"
#include "config_network.h"
#include "esp_coexist.h"
#include "esp_flash.h"
#include "wifi_manager.h"
#include <stdio.h>

#define TAG "BeiXiangDtu"

#define CONFIG_BUTTON GPIO_NUM_27

class BeiXiangDtu {
public:
	BeiXiangDtu() {}

	~BeiXiangDtu() {}

	void start() {
		// 初始化LED服务
		startLedManagerTask(20);
		addLedWithInit(GPIO_NUM_32);
		addLedWithInit(GPIO_NUM_33);
		// 判断当前是否为配网模式
		if (isConfigNetwork()) {
			return;
		}

		// 开启wifi
		wifi_manager_begin();
		// 注册wifi事件回调
		wifi_manager_register_event_cb(wifi_event_cb_static, this);
		m_otaUpdater = new OtaUpdater();
		// 必须先初始化 spiffs
		spiffs_init();
		// 启动远程参数配置监听服务
		m_remote_config = new RemoteConfig();
		m_remote_config->monitorRemoteConfigBoot();
		// 加载DTU配置
		profile_config = read_profile();
		// 创建网络道管理
		m_NetChannel = new NetChannel(profile_config);
		// 创建硬件接口
		m_hardware_interface = new ESP32Hardware();
		// 串口与通道映射
		for (int i = 0; i < MAX_CHANNEL_COUNT; i++) {
			on_serial_data_callBack[i].setCallback([this, i](std::vector<char> data) {
				this->m_NetChannel->sendData(i, data.data(), data.size());
			});
			const network_channel_t *channel = &profile_config->network_channels[i];
			const serial_port_parameters_t *serial_port = &profile_config->serial_port_parameters[channel->bound_serial];
			uart_serial_port_t uart_config = {
				.port_number = i,
				.baud_rate = serial_port->baud_rate,
				.data_bits = static_cast<uint8_t>(serial_port->data_bits),
				.parity = static_cast<uint8_t>(serial_port->parity),
				.stop_bits = static_cast<uint8_t>(serial_port->stop_bits),
				.pack_timeout = static_cast<uint8_t>(serial_port->pack_timeout),
				.callback = on_serial_data_callBack[i],
			};

			m_hardware_interface->onSerialData(&uart_config);
		}

		// 监听配网按钮
		xTaskCreate(monitor_config_button_task, "btn_monitor", 6144,
					(void *)CONFIG_BUTTON, 5, NULL);
	}

private:
	void initializeNetwork() {
		int max_retries = 10;
		for (int i = 0; i < max_retries; i++) {
			ESP_LOGI("NETWORK", "网络连通性检查尝试 %d/%d", i + 1, max_retries);
			if (checkPingConnectivity(HOST, PORT, 3)) {
				// 联网完成，检查要不要升级
				if (this->m_otaUpdater->checkForUpdate()) {
					this->m_otaUpdater->performUpdate();
					return;
				}
				break;
			}
			vTaskDelay(1000 / portTICK_PERIOD_MS); // 等待1秒后重试
		}

		this->m_NetChannel->init_channel();
		// 注册消息回调事件
		this->m_NetChannel->setDataCallback([this](uint8_t port_num, char *payload, unsigned int len) {
			if (this->m_hardware_interface->writeSerial(port_num, payload, len)) {
				return 0;
			}
			return 1;
		});
	}
	bool isConfigNetwork() {
		// 初始化监听配网按钮
		gpio_set_direction(CONFIG_BUTTON, GPIO_MODE_INPUT);
		gpio_set_pull_mode(CONFIG_BUTTON, GPIO_PULLUP_ONLY);
		if (gpio_get_level(CONFIG_BUTTON) == 0) {
			ESP_LOGI(TAG, "start ap and web config.....");
			led_manager_set_flow_direction(true);
			led_manager_set_flow_interval(200);

			LedConfig led_config = {.pin = GPIO_NUM_32,
									.mode = LED_BLINK,
									.interval = 200,

									.pwm_channel = LEDC_CHANNEL_2,
									.privileged = false};
			led_manager_set_mode(led_config);

			launch_wifi_ap_with_web_config();
			return true;
		}
		return false;
	}

	static void wifi_event_cb_static(wifi_manager_event_t event, void *ctx) {
		BeiXiangDtu *self = static_cast<BeiXiangDtu *>(ctx);
		self->onWifiEvent(event);
	}

	/**
	 * WIFI连接事件
	 */
	void onWifiEvent(wifi_manager_event_t event) {
		if (event == IP_EVENT_STA_GOT_IP) {
			initializeNetwork();
		} else if (event == WIFI_EVENT_CONNECTED) {
			ESP_LOGI("MY_APP", "WiFi connected!");
		} else if (event == WIFI_EVENT_DISCONNECTED) {
			ESP_LOGI("MY_APP", "WiFi disconnected!");
		} else if (event == WIFI_EVENT_FAILED) {
			ESP_LOGI("MY_APP", "WiFi failed to connect!");
		}
	}
	OtaUpdater *m_otaUpdater = {};
	RemoteConfig *m_remote_config = {};
	Callback<void, std::vector<char>> on_serial_data_callBack[MAX_CHANNEL_COUNT];
	IHardwareInterface *m_hardware_interface;
	NetChannel *m_NetChannel;
	const dtu_config_t *profile_config;
};
#endif